package datagraphics;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import database.Question;

/**
 * Panel de edicion de preguntas.
 * @author Grupo 11 de Programacion Orientada a Objetos
 *
 */

public class EditPanel extends JPanel{
	private LinkedList<Question> qlist;
	private int qselected, pagenumber, pagemax;
	private GridBagConstraints  gc;
	private ButtonGroup bgroup;
	private static final long serialVersionUID = 1L;
	private JRadioButton[] radios;
	
	/**
	 * Construye un panel basandose en un listado de preguntas.
	 * Si el listado esta vacio, tambien lo estara el panel.
	 * @param qlist - listado de preguntas
	 */
	
	public EditPanel(LinkedList<Question> qlist) {
		super(new GridBagLayout());
		
		qselected = 0;
		pagenumber = 0;
		bgroup = new ButtonGroup();
		
		if (qlist == null) {
			this.qlist = new LinkedList<Question>();
			setupRadios(0, 0);
		}
		else {
			this.qlist = qlist;
			
			if (qlist.size() >= 10)
				setupRadios(0, 10);
			else
				setupRadios(0, qlist.size());
		}
		
		// Actualiza la cantidad de paginas
		updatePageMax();
		
	}
	
	/**
	 * Devuelve la pregunta que actualmente esta seleccionada
	 * en el panel de edicion
	 * @return Question - pregunta seleccionada
	 */
	
	public Question getQuestionSelected() {
		if (qlist.size() > 0)
			return qlist.get(qselected + (pagenumber*10));
		
		return null;
	}
	
	
	/**
	 * Devuelve la cantidad de preguntas que almacena hasta
	 * el momento el panel
	 * @return int - cantidad preguntas almacenadas
	 */
	
	public int getQuestionAmount() {
		return qlist.size();
	}
	
	/**
	 * Agrega una pregunta al panel y la muestra siempre y cuando
	 * pertenezca a la misma categoria que las preguntas mostradas
	 * actualmente.
	 * @param q - pregunta a agregarse.
	 * @return boolean - Si pertenece a la misma categoria que 
	 * las preguntas actuales.
	 */
	
	public boolean addQuestion(Question q) {
		
		if (qlist.size() > 0) {
			if (q.getLevel() != qlist.getFirst().getLevel()) {
			return false;
			}
		}
		
		qlist.add(q);
		updatePageMax(); // renueva la maxima pagina alcanzable
		this.renderQList(pagenumber);
		this.validate();
		this.repaint();
		return true;
	}
	
	/**
	 * Remueve localmente, el borrado en la base de datos
	 * debe hacerse externamente.
	 * @param  q - Pregunta a quitar del panel
	 * @return Question - referencia a la pregunta borrada
	 * (Para poder identificarla y luego borrarla externamente)
	 */
	
	public Question removeQuestion(Question q) {
		if (qlist.size() < 11) {
			return null;
		}
		
		qlist.remove(this.getQuestionSelected());
		qselected = 0;
		updatePageMax(); // renueva la maxima pagina alcanzable
		
		/* Se fija si es necesario updatear la cantidad de paginas,
		 * renderea la pagina actual
		 */
		this.renderQList(pagenumber);
		this.validate();
		this.repaint();
		return q;
	}
	
	/**
	 * Establece una listado de preguntas que almacena el panel.
	 * Cambia cada vez que se switchea entre categorias.
	 * @param qlist - listado de preguntas 
	 */
	
	public void setQlist(LinkedList<Question> qlist) {
		
		if (qlist != null)
			this.qlist = qlist;
		else
			this.qlist = new LinkedList<Question>(); // Asi al cambiar de difcultad refleja el cambio
		
		qselected = 0;
		updatePageMax(); // renueva la maxima pagina alcanzable
		refreshQuestions();
	}
	
	/**
	 * Renderea nuevamente el panel para actualizar
	 * las preguntas mostradas.
	 */
	
	public void refreshQuestions() {
		
		
		renderQList(pagenumber);
		
		this.validate();
		this.repaint();
	}
	
	/**
	 * Retrocede una pagina en el panel, para mostrar
	 * las 10 preguntas anteriores, siempre y cuando no se
	 * este en la primera pagina
	 */
	
	public void backPage() {
		if (pagenumber > 0) {
			pagenumber -=1;
			refreshQuestions();
		}
		
		return;
	}
	
	/**
	 * Avanza una pagina siempre y cuando no se este en
	 * la última para mostrar el siguiente conjunto de preguntas
	 */
	
	public void nextPage() {
		if (pagenumber < pagemax) {
			pagenumber +=1;
			refreshQuestions();
		}
		
		return;
	}
	
	/**
	 * Se encarga del display de preguntas sobre el panel.
	 * @param page - numero de paginas que indica el conjunto
	 * de preguntas a mostrar.
	 */
	
	private void renderQList(int page) {
		int startIndex = page * 10;
		int endIndex = startIndex + 10;
		
		
		this.removeAll();
		
		if (qlist.size() < endIndex) {
			endIndex = qlist.size();
		}
		
		setupRadios(startIndex, endIndex);
		
		boolean first = true;
		for (JRadioButton r : radios) {
			if (first && r != null) {
				r.setSelected(true);
				first = false;
			}
		}
		
		return;
	}
	
	
	/**
	 * Accion ejecutada cuando se selecciona una pregunta
	 * en el panel
	 */
	
	private void radioActionPerformed() {
		ButtonModel radio;
		radio = bgroup.getSelection();
		qselected = Integer.valueOf(radio.getActionCommand());
		return;
	}
	
	
	/**
	 * Actualiza la maxima página alcanzable
	 */
	
	private void updatePageMax() {
		pagemax = (qlist.size() - 1) / 10;
	
		/* Si se estaba parado sobre la ultima pagina y se borran todas
		 * las preguntas de esa pagina, automaticamente se va a la pagina anterior
		 */
		if (pagenumber > pagemax) {
			pagenumber -=1;
			backPage();
		}
	}
	
	/**
	 * Configura los radio buttons que utiliza este panel
	 * para permitir seleccionar las diferentes preguntas.
	 * Las preguntas son organizadas en páginas de a 10 preguntas
	 */
	
	private void setupRadios(int startIndex, int endIndex) {
		int i = 0;
		
		radios = new JRadioButton[10];
		gc = new GridBagConstraints();
		LinkedList<Question> qaux;
		String radiolabel;
		
		qaux = new LinkedList<Question>(qlist.subList(startIndex, endIndex));
		gc.gridwidth = 4;
		gc.gridheight = 1;
		gc.gridx = 0;
		
		for (Question q : qaux) {
			radiolabel = (q.toString());
			radios[i] = new JRadioButton("<HTML>" + radiolabel + "</HTML>");
			radios[i].setActionCommand(String.valueOf(i));
			bgroup.add(radios[i]);
			
			setConstraint(gc, i);
			
			this.add(radios[i], gc, i);
			radios[i++].addActionListener(new ActionListener(){
	            public void actionPerformed(ActionEvent evt) {
	                radioActionPerformed();
	            }
	        });
		}
	}
	
	/**
	 * Establece la disposición y el espaciado entre preguntas
	 * en el panel
	 * @param gc - Posicionamiento y espaciado entre preguntas
	 * @param i - indice de la pregunta que se esta agregando
	 * (0 la primera, 9 la ultima)
	 */
	
	private void setConstraint(GridBagConstraints gc, int i) {
		gc.gridy = i;
		gc.anchor = GridBagConstraints.LINE_START;
		gc.weightx = 1.0;
		gc.weighty = 1.0;
		gc.fill = GridBagConstraints.HORIZONTAL;
	}
}
